package com.lixueju.security.box.web.authentication;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.lixueju.security.box.core.dto.ResultData;
import com.lixueju.security.box.core.enums.LoginTypeEnum;
import com.lixueju.security.box.core.enums.ResultDataEnum;
import com.lixueju.security.box.core.enums.TableFieldEnum;
import com.lixueju.security.box.core.model.User;
import com.lixueju.security.box.core.model.dto.UserToken;
import com.lixueju.security.box.core.model.request.*;
import com.lixueju.security.box.core.redis.RedisLock;
import com.lixueju.security.box.core.redis.RedisLockUtils;
import com.lixueju.security.box.core.redis.SecurityBoxRedisCache;
import com.lixueju.security.box.web.service.IAuthMenuService;
import com.lixueju.security.box.web.service.IUserService;
import com.lixueju.security.box.web.weixin.WeixinAuthService;
import com.lixueju.security.box.web.weixin.model.CodeResponse;
import com.lixueju.security.box.web.weixin.model.OauthAccessTokenResponse;
import com.lixueju.security.box.web.weixin.model.WeixinUserInfo;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.password.PasswordEncoder;

import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
 * @author lixueju
 * @since 2019/11/6 12:50
 **/
public class DefaultUserDetailsServiceImpl implements UserDetailsService {

    private Logger logger = LoggerFactory.getLogger(getClass());

    @Autowired
    private IUserService userService;

    @Autowired
    private IAuthMenuService authMenuService;

    @Autowired
    private PasswordEncoder passwordEncoder;

    @Autowired
    private WeixinAuthService weixinAuthService;

    @Autowired
    private SecurityBoxLoginAfter securityBoxLoginAfter;

    @Autowired
    private SecurityBoxRedisCache securityBoxRedisCache;

    @Override
    public UserDetails loadUserByUsername(String var) throws UsernameNotFoundException {
        RedisLock redisLock = RedisLockUtils.getLoginRequestLock();
        try {
            securityBoxRedisCache.lock(redisLock);
            LoginRequest loginRequest = JSONObject.parseObject(var, LoginRequest.class);
            User user = null;
            if (loginRequest.getId() == null) {
                if (loginRequest.getLoginType() == null) {
                    throw new UsernameNotFoundException("登录类型不可为空");
                }
                QueryWrapper<User> quUser = getUserQueryWrapper(loginRequest);
                if (loginRequest.getLoginType() == LoginTypeEnum.username.code()) {
                    user = this.userNamePasswordLogin(var, quUser);
                } else if (loginRequest.getLoginType() == LoginTypeEnum.sms.code()) {
                    user = this.smsLogin(var, quUser);
                } else if (loginRequest.getLoginType() == LoginTypeEnum.zhifubao.code()) {

                } else if (loginRequest.getLoginType() == LoginTypeEnum.weixin.code()) {
                    user = this.weixinLogin(var, quUser);
                } else if (loginRequest.getLoginType() == LoginTypeEnum.weixinDecode.code()) {
                    user = this.weixinOfDecodeLogin(var, quUser);
                }
            } else {
                user = userService.getById(loginRequest.getId());
            }
            if (user == null) {
                throw new UsernameNotFoundException("用户不存在");
            }
            loginRequest.setId(user.getId());
            ResultData<Boolean> resultData = securityBoxLoginAfter.loginAfter(var, user);
            if (resultData.getCode() != ResultDataEnum.SUCCESS.code()) {
                throw new UsernameNotFoundException(resultData.getMsg());
            }
            //从数据库获取权限
            Set<String> permissions = authMenuService.queryAllPermissionByUserId(user.getId());
            // 判断是否有用户身份权限
            if (!StringUtils.isBlank(user.getPermission())) {
                if (permissions == null) {
                    permissions = new HashSet<>();
                }
                permissions.add(user.getPermission());
            }
            String userPermissionString = null;
            if (permissions != null && permissions.size() > 0) {
                userPermissionString = StringUtils.join(permissions.toArray(), ",");
            } else {
                userPermissionString = "";
            }
            // 获取用户的权限信息集合
            List<GrantedAuthority> grantedAuthorities = AuthorityUtils.commaSeparatedStringToAuthorityList(userPermissionString);
            UserJwt userJwt = null;

            if (StringUtils.isBlank(user.getUsername()) || StringUtils.isBlank(user.getPassword())) {
                if (!StringUtils.isBlank(user.getUsername())) {
                    userJwt = new UserJwt(JSONObject.toJSONString(loginRequest), user.getUsername(), grantedAuthorities);
                } else {
                    userJwt = new UserJwt(JSONObject.toJSONString(loginRequest), user.getId() + "", grantedAuthorities);
                }
            } else {
                userJwt = new UserJwt(JSONObject.toJSONString(loginRequest), user.getPassword(), grantedAuthorities);
            }
            UserToken userToken = new UserToken();
            BeanUtils.copyProperties(user, userToken);
            if (loginRequest.isContainPermissions()) {
                userToken.setPermissions(permissions);
            }
            userJwt.setUserToken(userToken);

            return userJwt;
        } catch (UsernameNotFoundException e) {
            throw e;
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            securityBoxRedisCache.unlock(redisLock);
        }
        throw new UsernameNotFoundException("登录异常");
    }

    // 手机号登录
    private User smsLogin(String var, QueryWrapper<User> quUser) {
        SmsLoginRequest smsLoginRequest = JSONObject.parseObject(var, SmsLoginRequest.class);
        quUser.eq("mobile", smsLoginRequest.getMobile());
        return getUserOne(quUser);
    }

    // 微信密文方式登录
    private User weixinOfDecodeLogin(String var, QueryWrapper<User> quUser) {
        WeixinDecodeLoginRequest weixinDecodeLoginRequest = JSONObject.parseObject(var, WeixinDecodeLoginRequest.class);
        WeixinUserInfo weixinUserInfo = weixinAuthService.loginOfDecode(weixinDecodeLoginRequest);
        quUser.eq("wxBindingId", weixinUserInfo.getUnionId());
        User user = getUserOne(quUser);
        if (user == null) {
            user = newUser(weixinDecodeLoginRequest, weixinUserInfo);
            userService.addUser(user);
        }
        user.getExtend().put("openid", weixinUserInfo.getOpenId());
        return user;
    }

    // 微信登录
    private User weixinLogin(String var, QueryWrapper<User> quUser) {
        WeixinLoginRequest weixinLoginRequest = JSONObject.parseObject(var, WeixinLoginRequest.class);
        CodeResponse codeResponse = weixinAuthService.login(weixinLoginRequest);
        WeixinUserInfo userInfo = null;
        if (StringUtils.isBlank(codeResponse.getUnionid())) {
            OauthAccessTokenResponse oauthAccessTokenResponse = (OauthAccessTokenResponse) codeResponse;
            userInfo = weixinAuthService.getUserInfo(oauthAccessTokenResponse);
            quUser.eq("wxBindingId", userInfo.getUnionId());
        } else {
            quUser.eq("wxBindingId", codeResponse.getUnionid());
        }
        User user = getUserOne(quUser);
        if (user == null) {
            if (userInfo == null) {
                OauthAccessTokenResponse oauthAccessTokenResponse = (OauthAccessTokenResponse) codeResponse;
                userInfo = weixinAuthService.getUserInfo(oauthAccessTokenResponse);
            }
            user = newUser(weixinLoginRequest, userInfo);
            userService.addUser(user);
        }
        user.getExtend().put("openid", codeResponse.getOpenid());
        return user;
    }

    private User newUser(WeixinLoginRequest weixinLoginRequest, WeixinUserInfo userInfo) {
        User user = new User();
        user.setId(IdWorker.getId());
        user.setWxBindingId(userInfo.getUnionId());
        user.setNickName(userInfo.getNickName());
        user.setAvatarUrl(userInfo.getAvatarUrl());
        user.setUserType(weixinLoginRequest.getUserType());
        user.setCompanyId(weixinLoginRequest.getCompanyId());
        logger.info("userInfo:" + JSONObject.toJSONString(userInfo));
        return user;
    }

    // 用户名密码登录
    private User userNamePasswordLogin(String var, QueryWrapper<User> quUser) {
        UserNamePasswordLoginRequest userNamePasswordLoginRequest = JSONObject.parseObject(var, UserNamePasswordLoginRequest.class);
        // 根据用户名查询用户信息
        logger.info("登录用户名：" + userNamePasswordLoginRequest.getUsername());
        if (StringUtils.isBlank(userNamePasswordLoginRequest.getUsername())) {
            throw new UsernameNotFoundException("用户名不可为空");
        }
        if (StringUtils.isBlank(userNamePasswordLoginRequest.getPassword())) {
            throw new UsernameNotFoundException("密码不可为空");
        }
        quUser.eq("username", userNamePasswordLoginRequest.getUsername());
        User user = getUserOne(quUser);
        if (user == null) {
            throw new UsernameNotFoundException("用户不存在");
        }
        // 校验密码
        if (!passwordEncoder.matches(userNamePasswordLoginRequest.getPassword(), user.getPassword())) {
            throw new UsernameNotFoundException("用户名或密码不正确");
        }
        return user;
    }

    // 获取当前查询用户的条件
    private QueryWrapper<User> getUserQueryWrapper(LoginRequest loginRequest) {
        QueryWrapper<User> quUser = new QueryWrapper<>();
        quUser.eq("delFlag", TableFieldEnum.AllOfdelFlag.no.code());
        if (loginRequest.getCompanyId() != null) {
            quUser.eq("companyId", loginRequest.getCompanyId());
        }
        if (loginRequest.getUserType() != null) {
            quUser.eq("userType", loginRequest.getUserType());
        }
        return quUser;
    }

    // 获取唯一用户
    private User getUserOne(QueryWrapper<User> quUser) {
        List<User> userList = userService.list(quUser);
        if (userList == null || userList.size() < 1) {
            return null;
        }
        if (userList.size() > 1) {
            throw new UsernameNotFoundException("存在多个用户，请注意用户身份参数");
        }
        return userList.get(0);
    }
}
